Python 数据可视化 生成数据

第 15 章 生成数据

1. 数据分析和数据可视化概念

  1. 数据可视化:指的是通过可视化表示来探索数据。它与数据分析紧密相关,

  2. 数据分析:而数据分析指的是使用代码来探索数据集的规律和关联。数据集可以是用一行代码就能表示的小型数字列表,也可以是数千兆字节的数据

  3. 目的:
    漂亮地呈现数据并非仅仅关乎漂亮的图片。通过以引人注目的简单方式呈现数据,能让观看者明白其含义:发现数据集中原本未知的规律和意义。
    数据可视化工具

  4. 数据科学家使用Python编写了一系列优秀的可视化和分析工具,其中很多可供你使用。最流行的工具之一是Matplotlib,它是一个数学绘图库,我们将使用它来制作简单的图表,如折线图和散点图。

  5. 安装Matpotlib

安装Matplotlib

pip3 install --user sphinx
Warning

注意: 版本要使用3.5.3 版本,如果版本太高,代码需要改写。

1.1. 绘制简单的折线图

一个简单的例子
mpl_squares.py

import  matplotlib.pyplot as plt
squares = [1, 4, 9, 16, 25]
fig, ax = plt.subplots()
ax.plot(squares)
plt.show()

1.2. 绘图的组成部分

Matpotlib-figure-.png

1.2.1. Figure

结构 说明
Figure 整个绘图区域,可以包含多个坐标轴,
  1. 可以包括(标题,图形图例,颜色条等,甚至可以嵌套子绘图区域)。
fig = plt.figure()  # an empty figure with no Axes
fig, ax = plt.subplots()  # a figure with a single Axes
fig, axs = plt.subplots(2, 2)  # a figure with a 2x2 grid of Axes

1.2.2. Axes

结构 说明
Axes 是在绘图区域中设置的坐标轴,如果是三维图像,则是三个坐标轴,
  1. 为坐标轴中的数据提供刻度和刻度标签。
  2. Axes 还有一个标题(通过set_title() 设置)
  3. 一个x 标签(通过set_xlabel()设置)
  4. 一个y标签(通过set_ylabel()设置)

1.2.3. Axis

结构 说明
Axis 设置坐标轴的刻度和标签。

1.2.4. Artist

结构 说明
Artist 基本上所有的可见的元素的都成为Artist 。
  1. Artist 包括 :
    Figure ,Axes ,Axis ,Text ,Line2D, Collections ,Path 等对象。
  2. 当这些元素被渲染时,所有的Artist 都会被绘制在 Figure 上。
  3. 大多数Artis 会被花在同一个坐标轴中,但是如果Artist 不符合当前坐标轴规范,则会被绘制到另外的坐标轴上。

1.3. Matpotlib 函数

1.3.1. subplot 函数

首先导入模块pyplot ,并为其指定别名plt ,以免反复输入pyplot 。

matplotlib.pyplot.subplots(_nrows=1_, _ncols=1_, _*_, _sharex=False_, _sharey=False_, _squeeze=True_, _width_ratios=None_, _height_ratios=None_, _subplot_kw=None_, _gridspec_kw=None_, _**fig_kw_)[[source]](https://github.com/matplotlib/matplotlib/blob/v3.6.0/lib/matplotlib/pyplot.py#L1284-L1435)
  1. 创建一个图和一组子图 。
  2. 这个函数可以方便的创建figure 的布局。
1.3.1.1. 入参
参数 说明
nrows 将figure 分割上下成几份。
ncols 将figure 分割成左右几份。
sharex, sharey X 轴和 Y 轴是否共享属性
width_ratios 定义X轴的刻度的相对宽度
height_ratios 定义Y轴的刻度的相对高度。
**fig_kw 将定义好的子图返回给figure 调用
1.3.1.2. 返回值
说明
fig figure
ax 返回的坐标轴
# using the variable ax for single a Axes
fig, ax = plt.subplots()

# using the variable axs for multiple Axes
fig, axs = plt.subplots(2, 2)

# using tuple unpacking for multiple Axes
fig, (ax1, ax2) = plt.subplots(1, 2)
fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2)

2. 修改标签文字和线条粗细

mpl_squares.py

# 导入matplotlib库
import matplotlib.pyplot as plt       
#设置字体 ,如果不设置字体,则汉字无法显示
plt.rcParams["font.sans-serif"]=["SimHei"] 
#该语句解决图像中的“-”负号的乱码问题
plt.rcParams["axes.unicode_minus"]=False 
# 创建一个列表
squares = [1, 4, 9, 16, 25]
# 创建一个figure 并附带一个坐标轴
fig, ax = plt.subplots()
# 在坐标轴中绘制图形,并设置线段为3
ax.plot(squares, linewidth=3)
# 设置坐标轴的标题为"平方数“,字体大小为24
ax.set_title("平方数", fontsize=24)
# 设置X 坐标轴的标签为"值",字体大小为24
ax.set_xlabel("值", fontsize=14)
# 设置Y 坐标轴的标签为"平方值",字体大小为24
ax.set_ylabel("平方值", fontsize=14)
# 设置刻度标记的大小。
ax.tick_params(axis='both', labelsize=14)
plt.show()
Warning

如果想要在matolotlib 中使用汉字,需要设置对应字体。否则显式不出来汉字。

2.1. 使用到的函数

2.1.1. plot()

plot(*args, scalex=True, scaley=True, data=None, **kwargs)

说明:
主要是在坐标轴中绘制图形。
详情参考matplotlib.pyplot.plot — Matplotlib 3.6.0 documentation

2.1.2. tick_params()

tick_params(axis='both', **kwargs)

说明:
设置X,Y 坐标上的刻度大小和样式

2.2. 校正图形

mpl_squares.py

import matplotlib.pyplot as plt
plt.rcParams["font.sans-serif"]=["SimHei"] #设置字体
plt.rcParams["axes.unicode_minus"]=False #该语句解决图像中的“-”负号的乱码问题
imput_values = [1, 2, 3, 4, 5]
squares = [1, 4, 9, 16, 25]
fig, ax = plt.subplots()
ax.plot(imput_values, squares, linewidth=3)
ax.set_title("平方数", fontsize=24)
ax.set_xlabel("值", fontsize=14)
ax.set_ylabel("平方值", fontsize=14)
ax.tick_params(axis='both', labelsize=14)
plt.show()

2.3. 图表的内置样式

mpl_squares.py

import matplotlib.pyplot as plt
plt.style.use('tableau-colorblind10')

plt.rcParams["font.sans-serif"]=["SimHei"] #设置字体
plt.rcParams["axes.unicode_minus"]=False #该语句解决图像中的“-”负号的乱码问题
input_values = [1, 2, 3, 4, 5]
squares = [1, 4, 9, 16, 25]
fig, ax = plt.subplots()
ax.plot(input_values, squares, linewidth=3)
ax.set_title("平方数", fontsize=24)
ax.set_xlabel("值", fontsize=14)
ax.set_ylabel("平方值", fontsize=14)
ax.tick_params(axis='both', labelsize=14)
plt.show()


Warning

注意: plt.style.use('fivethirtyeight') 必须放在最前面,否则字体设置会被覆盖,会造成中文无法显示。

2.3.1. 内置样式

# 显示所有样式
print(plt.style.available)
['Solarize_Light2', '_classic_test_patch', '_mpl-gallery', '_mpl-gallery-nogrid', 'bmh', 'classic', 'dark_background', 'fast', 'fivethirtyeight', 'ggplot', 'grayscale', 'seaborn', 'seaborn-bright', 'seaborn-colorblind', 'seaborn-dark', 'seaborn-dark-palette', 'seaborn-darkgrid', 'seaborn-deep', 'seaborn-muted', 'seaborn-notebook', 'seaborn-paper', 'seaborn-pastel', 'seaborn-poster', 'seaborn-talk', 'seaborn-ticks', 'seaborn-white', 'seaborn-whitegrid', 'tableau-colorblind10']

内置样式表

样式 图底色 边框底色 网格 线 备注
seaborn-dark 灰色 白色 无网格 蓝色
seaborn-darkgrid 灰色 白色 白色网格 蓝色
seaborn-ticks 白色 白色 无网格 蓝色
fivethirtyeight 白色 白色 白色网格 蓝色
Solarize_Light2 黄色 黄色 白色网格 蓝色
_classic_test_patch 白色 白色 无网格 蓝色
_mpl-gallery 白色 白色 有网格 蓝色 只有图像没有坐标
_mpl-gallery-nogrid 白色 白色 无网格 蓝色 只有图像没有坐标
bmh 灰色, 白色 灰网格 蓝色
classic 白底 灰色 无网格 蓝色
dark_background 黑色 黑色 无网格 蓝色
fast 白色 白色 无网格 蓝色 默认模式
ggplot 灰色 白色 白色网格 红色
grayscale 白色 灰色 无网格 黑色
seaborn 灰色 白色 白色网格 蓝色
seaborn-bright 白色 白色 无网格 蓝色 默认格式
seaborn-colorblind 白色 白色 无网格 蓝色
seaborn-dark-palette 同上 同上 同上 同上
seaborn-deep ·· ·· ·· ·· ··
seaborn-muted ·· ·· ·· ·· ··
seaborn-notebook .. .. .. .. ..
seaborn-paper ·· ·· ·· ·· ··
seaborn-pastel 浅蓝色
seaborn-poster ·· ·· ·· ·· 小号字体
seaborn-talk ·· ·· ·· ·· 小号字体
tableau-colorblind10 ·· ·· ·· ·· ··

2.4. 使用scatter() 绘制散点图并设置样式

catter_squares.py

import matplotlib.pyplot as plt
plt.style.use('seaborn')
fig, ax = plt.subplots()
# 显示一个点
ax.scatter(2, 4)
plt.show()

函数:

matplotlib.pyplot.scatter(x, y, s=None, c=None, marker=None, cmap=None, norm=None, vmin=None, vmax=None, alpha=None, linewidths=None, verts=None, edgecolors=None, _, data=None,_ *kwargs)
## 参数说明

x, y : 相同长度的数组,数组大小(n,),也就是绘制散点图的数据;

s:绘制点的大小,可以是实数或大小为(n,)的数组, 可选的参数 ;

c:绘制点颜色, 默认是蓝色'b' , 可选的参数 ;

marker:表示的是标记的样式,默认的是'o' , 可选的参数 ;

cmap:当c是一个浮点数数组的时候才使用, 可选的参数 ;

norm:将数据亮度转化到0-1之间,只有c是一个浮点数的数组的时候才使用, 可选的参数 ;

vmin , vmax:实数,当norm存在的时候忽略。用来进行亮度数据的归一化 , 可选的参数 ;

alpha:实数,0-1之间, 可选的参数 ;

linewidths:标记点的长度, 可选的参数 ;

catter_squares.py


import matplotlib.pyplot as plt
plt.style.use('seaborn')
plt.rcParams["font.sans-serif"]=["SimHei"] #设置字体
plt.rcParams["axes.unicode_minus"]=False #该语句解决图像中的“-”负号的乱码问题
fig, ax = plt.subplots()
# s 选项为点的大小
ax.scatter(2, 4, s=200)
# 设置图表标题并给坐标轴加上标签。
ax.set_title("平方数", fontsize=34)
ax.set_xlabel("值", fontsize=24)
ax.set_ylabel("值的平方", fontsize =24)

# 设置刻度标记的大小。
ax.tick_params(axis='both', which='major', labelsize=14)

plt.show()

Warning

plt.style.use('seaborn') 加在所有代码的最前面,不要覆盖字体设置代码。

2.5. 使用scatter() 绘制一系列点

catter_squares.py

import matplotlib.pyplot as plt

x_values = [1, 2, 3, 4, 5]
y_values = [1, 4, 9, 16, 25]

plt.style.use('seaborn')
plt.rcParams["font.sans-serif"] = ["SimHei"]  # 设置字体
plt.rcParams["axes.unicode_minus"] = False  # 该语句解决图像中的“-”负号的乱码问题
fig, ax = plt.subplots()
ax.scatter(x_values, y_values, s=100)
# 设置图表标题并给坐标轴加上标签。
ax.set_title("平方数", fontsize=34)
ax.set_xlabel("值", fontsize=24)
ax.set_ylabel("值的平方", fontsize=24)

# 设置刻度标记的大小。
ax.tick_params(axis='both', which='major', labelsize=14)

plt.show()

2.6. 自动计算数据

import matplotlib.pyplot as plt

x_values = range(1, 1001)
y_values = [x**2 for x in x_values]

plt.style.use('seaborn')
plt.rcParams["font.sans-serif"] = ["SimHei"]  # 设置字体
plt.rcParams["axes.unicode_minus"] = False  # 该语句解决图像中的“-”负号的乱码问题
fig, ax = plt.subplots()
ax.scatter(x_values, y_values, s=10)
# 设置图表标题并给坐标轴加上标签。
ax.set_title("平方数", fontsize=34)
ax.set_xlabel("值", fontsize=24)
ax.set_ylabel("值的平方", fontsize=24)

# 设置刻度标记的大小。
ax.tick_params(axis='both', which='major', labelsize=14)
# 关闭科学计数法
ax.ticklabel_format(style='plain', axis="y")
# 开启科学计数法
# ax.ticklabel_format(style='sci', axis="y")

# 设置每个坐标轴的取值范围。
ax.axis([0, 1100, 0, 1100000])

plt.show()

Note

2.7. 自定义颜色

ax.scatter(x_values, y_values, c='red', s=10)

2.8. 渐变颜色

ax.scatter(x_values, y_values, c=y_values ,cmap=plt.cm.Blues, s=10)
Note

在官网还有很多颜色映射 颜色映射

2.9. 自动保存图表

plt.savefig('squraes_plot.png', bbox_inches='tight')

2.10. 练习题

练习15-1:立方 数的三次方称为立方 。请绘制一个图形,显示前5个整数的立方值。再绘制一个图形,显示前5000个整数的立方值

import matplotlib.pyplot as plt

x_values = range(1, 5000)
y_values = [x**3 for x in x_values]

plt.style.use('seaborn')
plt.rcParams["font.sans-serif"] = ["SimHei"]  # 设置字体
plt.rcParams["axes.unicode_minus"] = False  # 该语句解决图像中的“-”负号的乱码问题
fig, ax = plt.subplots()
ax.scatter(x_values, y_values, c=y_values ,cmap=plt.cm.Pastel1, s=10)
# 设置图表标题并给坐标轴加上标签。
ax.set_title("立方数", fontsize=24)
ax.set_xlabel("值", fontsize=24)
ax.set_ylabel("值的平方", fontsize=24)

# 设置刻度标记的大小。
ax.tick_params(axis='both', which='major', labelsize=14)
# 关闭科学计数法
ax.ticklabel_format(style='plain', axis="y")
# 开启科学计数法
#ax.ticklabel_format(style='sci', axis="y")

# 设置每个坐标轴的取值范围。
ax.axis([0, 1100, 0, 1100000])

plt.savefig('squraes_plot.png', bbox_inches='tight')

3. 随机漫步

在自然界、物理学、生物学、化学和经济领域,随机漫步都有其实际用途。例如,漂浮在水滴上的花粉因不断受到水分子的挤压而在水面上移动。水滴中的分子运动是随机的,因此花粉在水面上的运动路径犹如随机漫步。我们稍后编写的代码将模拟现实世界的很多情形。

3.1. 创建RandomWalk 类

random_walk.py

from random import choice


class RandomWalk:
    """一个生成随机漫步数据的类。"""

    def __init__(self, num_points=5000):
        """Initialize random walk properties. """
        self.num_points = num_points
        # 所有随机漫步都始于(0,0).
        self.x_values = [0]
        self.y_values = [0]

    def fill_walk(self):
        """Compute all points contained in the random walk. """
        # 不断漫步,直到列表达到指定长度。
        while len(self.x_values) < self.num_points:
            # 决定前进方向以及沿这个方向前进的距离。
            x_direction = choice([1, -1])
            x_distance = choice([0, 1, 2, 3, 4])
            x_step = x_direction * x_distance

            y_direction = choice([1, -1])
            y_distance = choice([0, 1, 2, 3, 4])
            y_step = y_direction * y_distance
            # 拒绝原地踏步
            if x_step == 0 and y_step == 0:
                continue
            # 计算下一个点的x值和y值。
            x = self.x_values[-1] + x_step
            y = self.y_values[-1] + y_step

            self.x_values.append(x)
            self.y_values.append(y)

rw_visual.py

import matplotlib.pyplot as plt
from random_walk import RandomWalk
# 创建一个RandomWalk实例。
rw = RandomWalk()
rw.fill_walk()
# 将所有的点都绘制出来。
plt.style.use('classic')
fig, ax = plt.subplots()
ax.scatter(rw.x_values ,rw.y_values, s=15)
plt.show()

3.2. 设置随机漫步图的样式

3.2.1. 渐变色

import matplotlib.pyplot as plt
from random_walk import RandomWalk
# 创建一个RandomWalk实例。
while True:
    rw = RandomWalk()
    rw.fill_walk()
    # 将所有的点都绘制出来。
    plt.style.use('classic')
    fig, ax = plt.subplots()
    point_numbers = range(rw.num_points)
    ax.scatter(rw.x_values ,rw.y_values, c=point_numbers, cmap=plt.cm.Blues, edgecolor='none', s=15)
    plt.show()

    keep_running = input("Make another walk?(y/n):")
    if keep_running == 'n':
        break

3.2.2. 重新绘制起点和终点

import matplotlib.pyplot as plt
from random_walk import RandomWalk
# 创建一个RandomWalk实例。
while True:
    rw = RandomWalk()
    rw.fill_walk()
    # 将所有的点都绘制出来。
    plt.style.use('classic')
    fig, ax = plt.subplots()
    point_numbers = range(rw.num_points)
    ax.scatter(rw.x_values ,rw.y_values, c=point_numbers, cmap=plt.cm.Blues, edgecolor='none', s=15)
    # 突出七点和终点。
    ax.scatter(0, 0, c='red', edgecolor='none', s=100)
    ax.scatter(rw.x_values[-1], rw.y_values[-1], c='red', edgecolor='none', s=100)
    plt.show()

    keep_running = input("Make another walk?(y/n):")
    if keep_running == 'n':
        break

3.2.3. 隐藏坐标轴

import matplotlib.pyplot as plt
from random_walk import RandomWalk
# 创建一个RandomWalk实例。
while True:
    rw = RandomWalk()
    rw.fill_walk()
    # 将所有的点都绘制出来。
    plt.style.use('classic')
    fig, ax = plt.subplots()
    point_numbers = range(rw.num_points)
    ax.scatter(rw.x_values ,rw.y_values, c=point_numbers, cmap=plt.cm.Blues, edgecolor='none', s=15)
    # 突出起点和终点。
    ax.scatter(0, 0, c='red', edgecolor='none', s=100)
    ax.scatter(rw.x_values[-1], rw.y_values[-1], c='red', edgecolor='none', s=100)
    # 隐藏坐标轴。
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)

    plt.show()

    keep_running = input("Make another walk?(y/n):")
    if keep_running == 'n':
        break

3.2.4. 增加随机漫步的点数

import matplotlib.pyplot as plt
from random_walk import RandomWalk
# 创建一个RandomWalk实例。
while True:
    rw = RandomWalk(50000)
    rw.fill_walk()
    # 将所有的点都绘制出来。
    plt.style.use('classic')
    fig, ax = plt.subplots()
    point_numbers = range(rw.num_points)
    ax.scatter(rw.x_values ,rw.y_values, c=point_numbers, cmap=plt.cm.Blues, edgecolor='none', s=15)
    # 突出起点和终点。
    ax.scatter(0, 0, c='red', edgecolor='none', s=100)
    ax.scatter(rw.x_values[-1], rw.y_values[-1], c='red', edgecolor='none', s=100)
    # 隐藏坐标轴。
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)

    plt.show()

    keep_running = input("Make another walk?(y/n):")
    if keep_running == 'n':
        break

3.2.5. 调整尺寸以适合屏幕

    fig, ax = plt.subplots(figsize=(15, 9),dpi=128)

Note

1 英寸= 2.54 厘米。
dpi=128 ,表示每英寸的像素为128 像素。

4. 使用Plotly 模拟掷子

本节将使用Python包Plotly来生成交互式图表。

需要创建在浏览器中显示的图表时,Plotly很有用,因为它生成的图表将自动缩放以适合观看者的屏幕

Plotly生成的图表还是交互式的:用户将鼠标指向特定元素时,将突出显示有关该元素的信息。

4.1. 安装Plotly

python -m pip install --user plotly

4.2. 创建Die 类

Die.py

from random import randint 

class Die:
   """ Denotes the class of a die. """

   def __init__(self, num_sides=6):
       """ The default is 6 sides."""
       self.num_sides = num_sides

   def roll(self):
       """ Returns a random value between 1 and the number of faces on the die."""
       return randint(1, self.num_sides)

4.3. 掷骰子

die_visual.py

from Die import Die
die = Die()
# Roll the dice several times and store the results in a list.
results = []
for roll_num in range(100):
    result = die.roll()
    results.append(result)
print(results)

4.4. 分析结果

from Die import Die
die = Die()
# Roll the dice several times and store the results in a list.
results = []
for roll_num in range(100):
    result = die.roll()
    results.append(result)
print(results)
frequencies = []
for value in range(1, die.num_sides + 1):
    """ Counts the number of times the current value appears in the list."""
    frequency = results.count(value)
    """ Adds the number of occurrences to the list."""
    frequencies.append(frequency)
print(frequencies)

4.5. 绘制直方图

from plotly.graph_objs import Bar, Layout
from plotly import offline

from Die import Die

die = Die()
# Roll the dice several times and store the results in a list.
results = []
for roll_num in range(1000):
    result = die.roll()
    results.append(result)
print(results)
frequencies = []
for value in range(1, die.num_sides + 1):
    """ Counts the number of times the current value appears in the list."""
    frequency = results.count(value)
    """ Adds the number of occurrences to the list."""
    frequencies.append(frequency)
print(frequencies)
# Visualize the results.
# 创建列表,list 是把对应reange 函数转换成列表。
x_values = list(range(1, die.num_sides + 1))
# 绘制条形图的数据集
data = [Bar(x=x_values, y=frequencies)]
# 设置坐标轴标签
x_axis_config = {'title': '结果'}
y_axis_config = {'title': '结果的频率'}
# 创建图表的布局和配置的对象,这事设置了图表名称,并传入了x 和y轴的配置字典。
my_layout = Layout(title='掷一个D61000次结果', xaxis=x_axis_config, yaxis=y_axis_config)
# 将对应的data 和 布局对象的字典 写入到 对应的文件中。
offline.plot({'data': data, 'layout': my_layout}, filename='d6.html')

data 数据结构

[Bar({
'x': [1, 2, 3, 4, 5, 6], 'y': [174, 144, 179, 158, 183, 162]
})]

4.6. 同时掷两个骰子

from plotly.graph_objs import Bar, Layout
from plotly import offline

from Die import Die

die1 = Die()
die2 = Die()
# Roll the dice several times and store the results in a list.
results = []
# 掷两个骰子 并算出两个累加和。
for roll_num in range(1000):
    result = die1.roll() + die2.roll()
    results.append(result)
frequencies = []
max_result = die1.num_sides + die2.num_sides
# 注意这里是从2 开始, 到13 , 因为两个骰子最小累加和为2 .
# 统计每个数据的出现频率。
for value in range(2, max_result + 1):
    """ Counts the number of times the current value appears in the list."""
    frequency = results.count(value)
    """ Adds the number of occurrences to the list."""
    frequencies.append(frequency)
print(frequencies)
# Visualize the results.
#  创建x轴的列表,list 是把对应range 函数转换成列表。
x_values = list(range(2, max_result + 1))
# 创建图表数据集
data = [Bar(x=x_values, y=frequencies)]
print(data)
# 设置x轴样式, ditck 设置的是x轴显示所有刻度值。
x_axis_config = {'title': '结果','dtick': 1}
y_axis_config = {'title': '结果的频率'}
my_layout = Layout(title='掷两个D61000次结果', xaxis=x_axis_config, yaxis=y_axis_config)
offline.plot({'data': data, 'layout': my_layout}, filename='d6.html')

4.7. 练习题

练习15-7:同时掷三个骰子 同时掷三个D6时,可能得到的最小点数为3,最大点数为18。请通过可视化展示同时掷三个D6的结果

from plotly.graph_objs import Bar, Layout
from plotly import offline

from Die import Die

die1 = Die(6)
die2 = Die(6)
die3 = Die(6)
# Roll the dice several times and store the results in a list.
results = []
for roll_num in range(1000):
    result = die1.roll() + die2.roll() + die3.roll()
    results.append(result)
frequencies = []
max_result = die1.num_sides + die2.num_sides + die3.num_sides
for value in range(3, max_result + 1):
    """ Counts the number of times the current value appears in the list."""
    frequency = results.count(value)
    """ Adds the number of occurrences to the list."""
    frequencies.append(frequency)
print(frequencies)
# Visualize the results.
x_values = list(range(3, max_result + 1))
data = [Bar(x=x_values, y=frequencies)]
print(data)

x_axis_config = {'title': '结果', 'dtick': 1}
y_axis_config = {'title': '结果的频率'}
my_layout = Layout(title='掷三个D6 1000次结果', xaxis=x_axis_config, yaxis=y_axis_config)
offline.plot({'data': data, 'layout': my_layout}, filename='d6.html')

练习15-8:将点数相乘 同时掷两个骰子时,通常将其点数相加。请通过可视化展示将两个骰子的点数相乘的结果。

from plotly.graph_objs import Bar, Layout
from plotly import offline

from Die import Die

die1 = Die(6)
die2 = Die(6)
# Roll the dice several times and store the results in a list.
results = []
for roll_num in range(1000):
    result = die1.roll() * die2.roll()
    results.append(result)
frequencies = []
max_result = die1.num_sides * die2.num_sides
for value in range(1, max_result + 1):
    """ Counts the number of times the current value appears in the list."""
    frequency = results.count(value)
    """ Adds the number of occurrences to the list."""
    frequencies.append(frequency)
print(frequencies)
# Visualize the results.
x_values = list(range(1, max_result + 1))
data = [Bar(x=x_values, y=frequencies)]
print(data)

x_axis_config = {'title': '结果', 'dtick': 1}
y_axis_config = {'title': '结果的频率'}
my_layout = Layout(title='掷两个D6 1000次相乘结果', xaxis=x_axis_config, yaxis=y_axis_config)
offline.plot({'data': data, 'layout': my_layout}, filename='d6.html')

练习15-10 使用两个库 :尝试使用Matplotlib通过可视化来模拟掷骰子的情况,并尝试使用Plotly通过可视化来模拟随机漫步的情况。要完成这个练习,需要查看这些库的文档。

Die.py

from random import randint


class Die:
    """ Denotes the class of a die. """

    def __init__(self, num_sides=6):
        """ The default is 6 sides."""
        self.num_sides = num_sides
        self.x_values = [0]
        self.y_values = [0]

    def roll(self):
        """ Returns a random value between 1 and the number of faces on the die."""
        return randint(1, self.num_sides)

randomwalk.py

from random import choice
from Die import  Die


class RandomWalk:
    """一个生成随机漫步数据的类。"""

    def __init__(self,num_points=5000):
        """Initialize random walk properties. """
        self.die = Die(12)
        self.num_points = num_points
        # 所有随机漫步都始于(0,0).
        self.x_values = [0]
        self.y_values = [0]

    def fill_walk(self):
        """Compute all points contained in the random walk. """
        # 不断漫步,直到列表达到指定长度。
        while len(self.x_values) < self.num_points:
            # 决定前进方向以及沿这个方向前进的距离。
            x_direction = choice([1])
            x_distance = self.die.roll()
            x_step = x_direction * x_distance

            y_direction = choice([1])
            y_distance = self.die.roll()
            y_step = y_direction * y_distance
            # 拒绝原地踏步
            if x_step == 0 and y_step == 0:
                continue
            # 计算下一个点的x值和y值。
            x = self.x_values[-1] + x_step
            y = self.y_values[-1] + y_step

            self.x_values.append(x)
            self.y_values.append(y)


rw_visual.py

import matplotlib.pyplot as plt
from randomwalk import RandomWalk
# 创建一个RandomWalk实例。
while True:
    rw = RandomWalk(50000)
    rw.fill_walk()
    # 将所有的点都绘制出来。
    plt.style.use('classic')
    fig, ax = plt.subplots()
    point_numbers = range(rw.num_points)
    ax.scatter(rw.x_values ,rw.y_values, c=point_numbers, cmap=plt.cm.Blues, edgecolor='none', s=15)
    # 突出起点和终点。
    ax.scatter(0, 0, c='red', edgecolor='none', s=100)
    ax.scatter(rw.x_values[-1], rw.y_values[-1], c='red', edgecolor='none', s=100)
    # 隐藏坐标轴。
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)

    plt.show()

    keep_running = input("Make another walk?(y/n):")
    if keep_running == 'n':
        break